package com.lzx.adx.report.task;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.PageUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lzs.adx.commmon.utils.DateUtils;
import com.lzs.adx.commmon.utils.JsonUtils;
import com.lzx.adx.report.bean.mapper.MeiTuanMapper;
import com.lzx.adx.report.bean.mapper.ReportMapper;
import com.lzx.adx.report.cache.AccountLocalCache;
import com.lzx.adx.report.cache.CommonLocalCache;
import com.lzx.adx.report.cache.OcpxAccountLocalCache;
import com.lzx.adx.report.cache.ProductLimitLocalCache;
import com.lzx.adx.report.dto.*;
import com.lzx.adx.report.dto.meituan.MeiTuanResponse;
import com.lzx.adx.report.entity.MeituanOrderEntity;
import com.lzx.adx.report.model.huawei.request.HwUploadRequest;
import com.lzx.adx.report.model.meituan.MeiTuanData;
import com.lzx.adx.report.model.meituan.MeituanResponse;
import com.lzx.adx.report.model.meituan.OrderCallBackRequest;
import com.lzx.adx.report.service.MeituanOrderService;
import com.lzx.adx.report.service.ReportService;
import com.lzx.adx.report.support.context.v3.CallBackV3Context;
import com.lzx.adx.report.support.strategy.v3.media.AbstractChannel;
import com.lzx.adx.report.util.HwSecureUtil;
import com.lzx.adx.report.util.meituan.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.*;
import java.util.*;
import java.util.stream.Collectors;

@Component
@RestController
@RequestMapping("/mt/task")
@Slf4j
public class MeiTuanTask implements ITask {

    //APP KEY
    private final static String APP_KEY = "bf11ccd6c42b5a61ded1bfac74bc7b0e";
    // APP密钥
    private final static String APP_SECRET = "0c0ce7b8427a48fcae0f747431c6cd08";
    //API域名
    private final static String HOST = "media.meituan.com";


    public static final String API_URL="/cps_open/common/api/v1/query_order";

    @Resource
    private MeituanOrderService meituanOrderService;

    @Autowired
    private MeiTuanMapper tuanMapper;

    @Autowired
    private ReportMapper reportMapper;

    @Autowired
    private ThreadPoolTaskExecutor reportExecutor;

    @Resource
    private CallBackV3Context callBackV3Context;


    @Resource
    private ReportService reportService;

    @RequestMapping("/callback")
    @Override
    public void run(String params) throws Exception {
        MeiTuanData orderPageData = getOrderPageData(1);
        if(Objects.isNull(orderPageData) || CollectionUtil.isEmpty(orderPageData.getDataList())){
            log.info("美团订单暂无数据");
            return;
        }
        Integer totalPage= PageUtil.totalPage(orderPageData.getSkuCount(),100);
        if(totalPage>1){
            //循环取订单的数据了
            for (int i=1;i<totalPage;i++){
                MeiTuanData meituanResponse = getOrderPageData(i);
                core(meituanResponse.getDataList());
            }
        }else{
            core(orderPageData.getDataList());
        }

    }

    private void core(List<OrderCallBackRequest> dataList) {
        for (OrderCallBackRequest orderCallBackRequest : dataList) {
            //处理美团订单

            orderCallBack(orderCallBackRequest);
        }

    }


    private static MeiTuanData getOrderPageData(long page)  {
        TreeMap<String,Object> params=new TreeMap<>();
        // 1 按订单支付时间查询， 2 按照更新时间查询， 默认为1
        params.put("queryTimeType",1);
        params.put("startTime",getBeginTime());
        params.put("endTime",getCurrentDayEndStime());
        params.put("searchType",1);
        params.put("limit","100");

        String bodyParams = JSON.toJSONString(params);

        Map<String, String> headers = new HashMap<String, String>();
        //（必填）根据期望的Response内容类型设置
        headers.put(HttpHeader.HTTP_HEADER_ACCEPT, "application/json");
        //（必填）Body MD5,服务端会校验Body内容是否被篡改
        headers.put(HttpHeader.HTTP_HEADER_CONTENT_MD5, MessageDigestUtil.base64AndMD5(bodyParams));
        //（POST请求必选）请求Body内容格式
        headers.put(HttpHeader.HTTP_HEADER_CONTENT_TYPE, ContentType.CONTENT_TYPE_JSON);

        // 其他接口协议定义的请求头，具体参见接口；或者媒体自己增加的请求头
        headers.put("Media-Request-Id", ""+System.currentTimeMillis());
        //自定义参与签名Header前缀（可选,默认只有"S-Ca-"开头的参与到Header签名）
        List<String> customHeadersToSignPrefix = new ArrayList<String>();
        // 必须放入的签名认证请求头S-Ca-App和S-Ca-Timestamp，则需要放入"S-Ca-Signature-Headers"请求头中!!!，必须放入
        customHeadersToSignPrefix.add("S-Ca-App");
        customHeadersToSignPrefix.add("S-Ca-Timestamp");
        // 其他接口协议定义的验签请求头，具体参见接口；或者媒体自己增加的验签请求头，保证数据安全，对应在headers里面必须有值
        customHeadersToSignPrefix.add("Cps-Request-Id");

        Request request = new Request(Method.POST_STRING, HttpSchema.HTTPS + HOST, API_URL, APP_KEY, APP_SECRET, Constants.DEFAULT_TIMEOUT);
        request.setHeaders(headers);
        request.setSignHeaderPrefixList(customHeadersToSignPrefix);
        //request不用在放入bodys和querys，这个是其他请求方式使用的，除非接口指定需要使用，默认当前暂不使用
        //request.setBodys(null);
        //request.setQuerys(null);

        //一定为原始计算md5的body
        request.setStringBody(bodyParams);
        //调用服务端
        Response response = Client.execute(request);
        if(response.getStatusCode()==200){
            MeituanResponse meituanResponse = JSON.parseObject(response.getBody(), MeituanResponse.class);
            if(meituanResponse.getCode()==0) {
                MeiTuanData data = meituanResponse.getData();
                return data;
            }

        }
        return null;
    }



    public static String getBeginTime() {
        CommonLocalCache instance = CommonLocalCache.getInstance();
        String elmUnionStime = instance.get("mt_stime");
        if (StringUtils.isBlank(elmUnionStime)) {
            String currentDayBegindayStime = getCurrentDayBegindayStime();
            instance.put("mt_stime", getCurrentDayBegindayStime());
            return currentDayBegindayStime;
        } else {
            // 将时间戳转换为 Instant 对象
            Instant instant = Instant.ofEpochMilli(Long.valueOf(elmUnionStime));
            // 这里使用系统默认时区，您可以根据需要选择其他时区
            LocalDateTime localDateTime = instant.atZone(ZoneId.systemDefault()).toLocalDateTime();

            if (localDateTime.isBefore(getYesterdayStartingTime())) {
                return getCurrentDayBegindayStime();
            } else {
                return elmUnionStime;
            }
        }
    }

    public static LocalDateTime getYesterdayStartingTime() {
        LocalDate yesterday = LocalDate.now().minusDays(0);
        LocalTime midnight = LocalTime.MIDNIGHT;
        return LocalDateTime.of(yesterday, midnight);
    }


    public static String getCurrentDayBegindayStime() {
        LocalDateTime yesterdayStartingTime =getStartingTime();
        // 将 LocalDateTime 转换为 Instant
        Instant instant = yesterdayStartingTime.atZone(ZoneId.systemDefault()).toInstant();
        // 获取时间戳值
        long timestamp = instant.toEpochMilli()/1000;
        return String.valueOf(timestamp);
    }


    public static String getCurrentDayEndStime() {
        LocalDateTime yesterdayStartingTime =getEndTime();
        // 将 LocalDateTime 转换为 Instant
        Instant instant = yesterdayStartingTime.atZone(ZoneId.systemDefault()).toInstant();
        // 获取时间戳值
        long timestamp = instant.toEpochMilli()/1000;
        return String.valueOf(timestamp);
    }



    public static LocalDateTime getStartingTime() {
        LocalDate yesterday = LocalDate.now().minusDays(0);
        LocalTime midnight = LocalTime.MIDNIGHT;
        return LocalDateTime.of(yesterday, midnight);
    }


    public static LocalDateTime getEndTime() {
        LocalDate yesterday = LocalDate.now().minusDays(0);
        LocalTime midnight = LocalTime.MAX;
        return LocalDateTime.of(yesterday, midnight);
    }



    public static String genSign(TreeMap<String, Object> params) {
        params.remove("sign");
        StringBuilder stringBuilder = new StringBuilder();
        // 替换为「我要推广」-「联盟API接口」页面下的签名秘钥值
        String apiToken = APP_SECRET;
        stringBuilder
                .append(apiToken)
                .append(params.entrySet().stream()
                        .map(entry -> entry.getKey() + entry.getValue())
                        .collect(Collectors.joining()))
                .append(apiToken);
        return md5(stringBuilder.toString());
    }



    public static String md5(String source) {
        String md5Result = null;
        try {
            byte[] hash = org.apache.commons.codec.binary.StringUtils.getBytesUtf8(source);
            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
            messageDigest.update(hash);
            hash = messageDigest.digest();
            md5Result = Hex.encodeHexString(hash);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return md5Result;
    }



    public MeiTuanResponse orderCallBack(OrderCallBackRequest orderCallBackRequest){
        log.info("接收到【美团】的请求参数为{}", JsonUtils.toJsonString(orderCallBackRequest));
        try {
            String sid = orderCallBackRequest.getSid();
            Map<String, Object> map = new HashMap<>();
            map.put("orderId", orderCallBackRequest.getOrderid());
            map.put("limit", true);
            List<MeituanOrderDTO> meituanOrderDTOList = meituanOrderService.list(map);
            MeituanOrderDTO meituanOrderDTOUpdate = tuanMapper.toMeituanOrder(orderCallBackRequest);
            if (CollectionUtil.isNotEmpty(meituanOrderDTOList) ) {
                MeituanOrderDTO meituanOrderDTO = meituanOrderDTOList.get(0);
                if(meituanOrderDTO.getHandType().intValue()==1 && orderCallBackRequest.getTradeType().intValue()==1){
                    log.info("dspId:{} 订单号:{} 已经处理过了无需再处理", sid, orderCallBackRequest.getOrderid());
                    return new MeiTuanResponse().err();
                }else{
                    //更新
                    meituanOrderDTOUpdate.setId(meituanOrderDTO.getId());
                    meituanOrderDTOUpdate.setTradeTypes(String.valueOf(orderCallBackRequest.getTradeType()));
                    meituanOrderDTOUpdate.setCreateTime(new Date());
                    meituanOrderDTOUpdate.setUpdateTime(new Date());
                    meituanOrderDTOUpdate.setExtend(JSON.toJSONString(orderCallBackRequest));
                    meituanOrderDTOUpdate.setHandType(0);
                    meituanOrderDTOUpdate.setProfit(orderCallBackRequest.getTradeType()==2?orderCallBackRequest.getCpaProfit():orderCallBackRequest.getProfit());
                    meituanOrderService.update(meituanOrderDTOUpdate);
                }
                return null;
            }else{
                //为空就新增
                //先吧数据存储起来
                meituanOrderDTOUpdate.setTradeTypes(String.valueOf(orderCallBackRequest.getTradeType()));
                meituanOrderDTOUpdate.setCreateTime(new Date());
                meituanOrderDTOUpdate.setUpdateTime(new Date());
                meituanOrderDTOUpdate.setExtend(JSON.toJSONString(orderCallBackRequest));
                meituanOrderDTOUpdate.setHandType(0);
                meituanOrderDTOUpdate.setProfit(orderCallBackRequest.getTradeType()==2?orderCallBackRequest.getCpaProfit():orderCallBackRequest.getProfit());
                meituanOrderService.save(meituanOrderDTOUpdate);
            }

            //根据时间点去推送
            String ordertime = meituanOrderDTOUpdate.getPaytime();

            //请求参数
            Map<String, Object> params = new HashMap<>();
//            params.put("ordertime", DateUtils.convertToFormattedDate(Long.parseLong(ordertime)));
            params.put("dsp_id", orderCallBackRequest.getSid());
            List<ReportDTO> list = reportService.list(params);

            List<ReportDTO> dataReport = list.stream().filter(t -> StringUtils.isBlank(t.getResultType())).collect(Collectors.toList());
            ReportDTO reportDTO = null;
            if (CollectionUtil.isNotEmpty(dataReport)) {
                reportDTO = dataReport.get(0);
            }else{
                log.info("订单号为{} ，未匹配到合适的点击",orderCallBackRequest.getOrderid());
                return new MeiTuanResponse().err();
            }

            OcpxAccountDTO accountDTO = OcpxAccountLocalCache.getInstance().get(orderCallBackRequest.getSid());
            String defaultKey =orderCallBackRequest.getTradeType()==2?"1":accountDTO.getDefaultKey();
            String time = String.valueOf(System.currentTimeMillis());


            ProductLimitLocalCache instance = ProductLimitLocalCache.getInstance();

            //价格别
            String price = instance.get(accountDTO.getProductChannel());
            String orderCommonPrice = orderCallBackRequest.getProfit();
            log.info("订单号为{} ，来源于产品{} 配置的金额{}，订单金额{}", orderCallBackRequest.getOrderid(), accountDTO.getProductChannel(), price, orderCommonPrice);
            reportDTO.setSid(orderCallBackRequest.getOrderid());

            if(StringUtils.isBlank(price)){
                AbstractChannel abstractReport = callBackV3Context.getCallBack(accountDTO.getMediaChannel());
                abstractReport.callback(reportDTO, accountDTO, defaultKey, time);
            }else{
                BigDecimal bigDecimal = new BigDecimal(price);
                BigDecimal profit = new BigDecimal(orderCallBackRequest.getProfit());
                //当拥挤大于配置的金额，才需要回调
                if (profit.compareTo(bigDecimal) > 0) {
                    log.info("订单号为{} ，开始回传给媒体了",orderCallBackRequest.getOrderid());
                    AbstractChannel abstractReport = callBackV3Context.getCallBack(accountDTO.getMediaChannel());
                    abstractReport.callback(reportDTO, accountDTO, defaultKey, time);
                }else{
                    log.info("订单号为{} ，基本不过关，数据库限制金额{}，实际佣金{}",orderCallBackRequest.getOrderid(),price, orderCommonPrice);
                }
            }
            //更新订单状态标识已推送
            updateOrderStatus(meituanOrderDTOUpdate.getId());
        }catch (Exception e){
            log.error("美团 出现异常的 订单号为{}",orderCallBackRequest.getOrderid());
            log.error("美团 处理-美团出现了异常，异常的错误为",e);
        }
        return new MeiTuanResponse().ok();
    }


    public void updateOrderStatus(Long id){
        //更新订单状态为已处理
        MeituanOrderEntity meituanOrderEntity = new MeituanOrderEntity();
        meituanOrderEntity.setId(id);
        meituanOrderEntity.setHandType(1);
        meituanOrderService.updateById(meituanOrderEntity);
    }


}
